'use strict'

let util = require('util');
let config = require('./config');
let loggers = require('./modules/lib/loggers');
let outputLogger = loggers.output;

// Middlewares
let bodyParser = require('body-parser');
let ejs = require('ejs');

let accessMiddlewares = require('./modules/middlewares/access');
let catcher = require('./modules/middlewares/catcher');
let fibers = require('./modules/middlewares/fibers');
let session = require('./modules/middlewares/session');
let iflyLogin = require('./modules/middlewares/iflylogin.js');

// Actions
let generalAction = require('./modules/actions/general');
let dispatchActions = require('./modules/actions/dispatch');
let userActions = require('./modules/actions/user');
let roleActions = require('./modules/actions/role');
let privilegeActions = require('./modules/actions/privilege');
let checkTimeSetActions = require('./modules/actions/checktimeset');
let schoolActions = require('./modules/actions/school');
let helloActions = require('./modules/actions/hello');
let natureClassActions = require('./modules/actions/natureclass');
let studentActions = require('./modules/actions/student');
let teacherActions = require('./modules/actions/teacher');
let leaderActions = require('./modules/actions/leader');
let gradeManagerActions = require('./modules/actions/grade_manager');
let deviceActions = require('./modules/actions/device');
let labelActions = require('./modules/actions/label');
// Application define
let express = require('express');
let cookieParser = require('cookie-parser');
let app = express();
let myApp = {
    combineSubOptions(options, optionNames) {
        let subOptions = {};
        optionNames
            .filter(optionName => optionName in options)
            .forEach(optionName => {
                subOptions[optionName] = options[optionName]
            });

        return subOptions;
    },
    get(url, action) {
        return myApp.handle('get', url, action.handler, action);
    },
    post(url, action) {
        return myApp.handle('post', url, action.handler, action);
    },
    handle(method, url, callback, options) {
        let grantOptions = null;
        let fieldOptions = null;
        if ( options ) {
            grantOptions = myApp.combineSubOptions(options, [
                    'login', 'privileges', 'roles'
            ]);

            fieldOptions = myApp.combineSubOptions(options, [
                    'fields'
            ]);
        }

        app[method](url, generalAction(callback, grantOptions, fieldOptions));
    }
};

app.set('views', __dirname + '/views');
app.engine('.html', ejs.__express);
app.set('view engine', 'ejs');

app.all('*', accessMiddlewares.control);

app.use(express.static(__dirname + '/static'));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(accessMiddlewares.watcher);
app.use(catcher);
app.use(fibers);
app.use(iflyLogin.filter);
app.use(session.filter);

// Dispatch
myApp.get('/user/dispatch', dispatchActions.actionDispatch);

// User routers
myApp.get('/user/login', userActions.actionLogin);
myApp.post('/user/logout', userActions.actionLogout);
myApp.get('/user/info', userActions.actionGetUserInfomation);
myApp.post('/user/create', userActions.actionCreateUser);
myApp.post('/user/remove', userActions.actionRemoveUser);
myApp.get('/user/all', userActions.actionUserAll);
myApp.post('/user/modify_info',userActions.actionModifyPersonalUserInfo);

//Role routers
myApp.post('/role/create', roleActions.actionCreateRole);
myApp.post('/role/refresh', roleActions.actionRefreshRole);
myApp.post('/role/remove', roleActions.actionRemoveRole);
myApp.get('/role/all', roleActions.actionRoleAll);

//Privilege routers
myApp.post('/privilege/create', privilegeActions.actionCreatePrivilege);
myApp.post('/privilege/refresh', privilegeActions.actionRefreshPrivilege);
myApp.post('/privilege/remove', privilegeActions.actionRemovePrivilege);
myApp.get('/privilege/all', privilegeActions.actionPrivilegeAll);

// Device routers
myApp.post('/device/school/enter', deviceActions.actionEnterSchool);
myApp.post('/device/school/exit', deviceActions.actionExitSchool);
//myApp.post('/device/classroom/enter', deviceActions.actionEnterClassroom);
//myApp.post('/device/classromm/exit', deviceActions.acionExitClassroom);

// Student routers
myApp.get('/student/index/time', studentActions.viewCheckTimes);
myApp.get('/student/index/today', studentActions.viewTodayAttendance);
myApp.get('/student/attendance/search', studentActions.viewQueryAttendance);
myApp.get('/student/absence_apply/add', studentActions.viewAddAbsenceApply);
myApp.get('/student/absence_apply/history', studentActions.viewHistoryAbsenceApply);
myApp.get('/student/test/test', studentActions.viewTest);

myApp.post('/student/absence_apply/submit', studentActions.actionSubmitAbsenceApply);
myApp.get('/student/:studentId/attendance/detail', studentActions.actionQueryAttendanceDetails);
myApp.get('/student/:studentId/attendance/error', studentActions.actionQueryAttendanceErrors);

// Teacher routers
myApp.post('/teacher/absence_apply/update', teacherActions.actionDealAbsenceApply);
myApp.post('/teacher/attendance/update', teacherActions.actionUpdateAttendances);

myApp.get('/teacher/index/index', teacherActions.viewIndex);
myApp.get('/teacher/attendance/search', teacherActions.viewSearchAttendance);
myApp.get('/teacher/attendance/daily_report', teacherActions.viewDailyReport);
myApp.get('/teacher/attendance/week_report', teacherActions.viewWeekReport);
myApp.get('/teacher/attendance/month_report', teacherActions.viewMonthReport);
myApp.get('/teacher/attendance/report', teacherActions.viewAttendanceReport);
myApp.get('/teacher/manual/manual', teacherActions.viewManual);
myApp.get('/teacher/absence_apply/history', teacherActions.viewHistoryAbsenceApply);
myApp.get('/teacher/absence_apply/today', teacherActions.viewTodayAbsenceApply);

// Leader routers
myApp.get('/leader/timesetting', leaderActions.actionTimeSetting);
myApp.get('/leader/info', leaderActions.actionLeaderInfo);

myApp.get('/leader/index/index', leaderActions.viewIndex);
myApp.get('/leader/basic_data/students', leaderActions.viewStudentList);
myApp.get('/leader/basic_data/classes', leaderActions.viewClassList);
myApp.get('/leader/attendance/report', leaderActions.viewAttendanceReport);
myApp.get('/leader/attendance/daily_report', leaderActions.viewDailyReport);
myApp.get('/leader/attendance/week_report', leaderActions.viewWeekReport);
myApp.get('/leader/attendance/month_report', leaderActions.viewMonthReport);
myApp.get('/leader/attendance/search', leaderActions.viewSearchAttendance);
myApp.get('/leader/system/check_time', leaderActions.viewCheckTimes);
myApp.get('/leader/system/festival', leaderActions.viewFestivals);
myApp.get('/leader/system/term', leaderActions.viewTerms);
myApp.get('/leader/device/manage', leaderActions.viewManageDevice);
myApp.get('/leader/user/privileges', leaderActions.viewPrivileges);

myApp.post('/leader/user/grant_leader', leaderActions.actionGrantLeader);
myApp.post('/leader/user/cancel_leader', leaderActions.actionCancelLeader);

// Grade Manager routers
myApp.get('/grade_manager/index/index', gradeManagerActions.viewIndex);
myApp.get('/grade_manager/attendance/today', gradeManagerActions.viewTodayAttendance);
myApp.get('/grade_manager/attendance/search', gradeManagerActions.viewSearchAttendance);

// School routers
myApp.post('/school/festival/update', schoolActions.actionUpdateFestivals);
myApp.get('/school/:schoolId/timesetting', schoolActions.actionTimeSettings);

myApp.get('/school/:schoolId/terms', schoolActions.actionGetTerms);
myApp.post('/school/:schoolId/terms/add', schoolActions.actionAddTerm);
myApp.post('/school/:schoolId/terms/update', schoolActions.actionUpdateTerm);
myApp.post('/school/:schoolId/terms/remove', schoolActions.actionRemoveTerm);

myApp.get('/school/all', schoolActions.actionGetAllSchools);

// CheckTimeSet routers
myApp.post('/checktimeset/:checkTimeSetId/update', checkTimeSetActions.actionUpdateCheckTimeSet);

//Label routers


// Create server and listen the port
let server = app.listen(config.server.port, function() {
    outputLogger.info('Listening on port %d', server.address().port);
});
